﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ADDDF.Infrastructure.Collections;

namespace ADDDF.Infrastructure.Test.EntitySetFramework
{
    [TestClass]
    public class EntitySetUnitTests
    {
        [TestMethod]
        public void EntitySet_CRUD()
        {
            bool removed;

            EntitySet<Vehicle> eSet1 = new EntitySet<Vehicle>();

            Assert.AreEqual(0, eSet1.GetAll().Count());

            Vehicle ent1 = new Vehicle(30001);

            Assert.IsNull(eSet1.FindByKey(30001));

            removed = eSet1.AddAndReplace(ent1);

            Assert.IsFalse(removed);
            Assert.AreEqual(1, eSet1.GetAll().Count());

            Assert.ReferenceEquals(ent1, eSet1.FindByKey(30001));
            Assert.ReferenceEquals(ent1, eSet1.GetAll().ToList()[0]);

            removed = eSet1.AddAndReplace(ent1);

            Assert.IsTrue(removed);
            Assert.AreEqual(1, eSet1.GetAll().Count());

            Vehicle ent2 = new Vehicle(30001);

            removed = eSet1.AddAndReplace(ent2);

            Assert.IsTrue(removed);
            Assert.AreEqual(1, eSet1.GetAll().Count());
            Assert.ReferenceEquals(ent2, eSet1.FindByKey(30001));
            Assert.ReferenceEquals(ent2, eSet1.GetAll().ToList()[0]);

            Vehicle ent3 = new Vehicle(45999);

            removed = eSet1.AddAndReplace(ent3);

            Assert.IsFalse(removed);
            Assert.AreEqual(2, eSet1.GetAll().Count());
            Assert.ReferenceEquals(ent2, eSet1.FindByKey(30001));
            Assert.ReferenceEquals(ent3, eSet1.FindByKey(45999));

            removed = eSet1.Remove(ent1);

            Assert.IsTrue(removed);
            Assert.AreEqual(1, eSet1.GetAll().Count());
            Assert.IsNull(eSet1.FindByKey(30001));
            Assert.ReferenceEquals(ent3, eSet1.FindByKey(45999));

            eSet1.RemoveAll();

            Assert.AreEqual(0, eSet1.GetAll().Count());
        }

        [TestMethod]
        public void EntityValueSet_CRUD()
        {
            bool removed;

            EntityValueSet<Vehicle> evSet1 = new EntityValueSet<Vehicle>(null,
                x => { return new Vehicle(x.VIN) { Brand = x.Brand }; });

            Assert.AreEqual(0, evSet1.GetAll().Count());

            Vehicle ent1 = new Vehicle(30001);
            ent1.Brand = "Honda";

            Assert.IsNull(evSet1.FindByKey(30001));

            removed = evSet1.AddAndReplace(ent1);

            Assert.IsFalse(removed);
            Assert.AreEqual(1, evSet1.GetAll().Count());

            // Make sure a copy not the original is added.
            Assert.IsFalse(Object.ReferenceEquals(ent1, evSet1.FindByKey(30001)));
            Assert.IsTrue(ent1.SameEntityAs(evSet1.FindByKey(30001)));

            // Make sure a copy not the original is returned.
            Assert.IsFalse(Object.ReferenceEquals(ent1, evSet1.GetAll().ToList()[0]));
            Assert.IsTrue(ent1.SameEntityAs(evSet1.GetAll().ToList()[0]));

            // Make sure clone method is called.
            Assert.AreEqual("Honda", evSet1.FindByKey(30001).Brand);

            ent1.Brand = "Buick";
            removed = evSet1.AddAndReplace(ent1);

            Assert.IsTrue(removed);
            Assert.AreEqual(1, evSet1.GetAll().Count());

            // Make sure prev one is replaced with new one
            Assert.AreEqual("Buick", evSet1.FindByKey(30001).Brand);

            Vehicle ent2 = new Vehicle(30001);
            ent2.Brand = "Chrysler";

            removed = evSet1.AddAndReplace(ent2);

            Assert.IsTrue(removed);

            // Make sure still only has one instance
            Assert.AreEqual(1, evSet1.GetAll().Count());

            // Make sure a new one replaces the old one
            Assert.IsFalse(Object.ReferenceEquals(ent2, evSet1.FindByKey(30001)));
            Assert.IsTrue(ent2.SameEntityAs(evSet1.FindByKey(30001)));

            Vehicle ent3 = new Vehicle(45999);
            ent3.Brand = "Crab";

            removed = evSet1.AddAndReplace(ent3);

            Assert.IsFalse(removed);
            Assert.AreEqual(2, evSet1.GetAll().Count());
            Assert.IsTrue(ent2.SameEntityAs(evSet1.FindByKey(30001)));
            Assert.IsTrue(ent3.SameEntityAs(evSet1.FindByKey(45999)));

            removed = evSet1.Remove(ent1);

            Assert.IsTrue(removed);
            Assert.AreEqual(1, evSet1.GetAll().Count());
            Assert.IsNull(evSet1.FindByKey(30001));
            Assert.IsTrue(ent3.SameEntityAs(evSet1.FindByKey(45999)));

            evSet1.RemoveAll();

            Assert.AreEqual(0, evSet1.GetAll().Count());
        }

        #region Vehicle Entity

        class Vehicle : EntityBase
        {
            private string _brand;

            public Vehicle(int vin)
                : base(vin)
            {
            }

            public int VIN
            {
                get { return (int)this.Key; }
            }

            public string Brand
            {
                get { return _brand; }
                set { _brand = value; }
            }
        }

        #endregion        
    }
}
